







#include <libfdt.h>
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/arm/hi1711.h"
#include "hw/boards.h"
#include "hw/qdev-properties.h"
#include "sysemu/sysemu.h"
#include "qemu/error-report.h"
#include "sysemu/qtest.h"
#include "hw/misc/unimp.h"
#include "hw/i2c/i2c.h"
#include "hw/arm/hi1711_boards.h"
#include "hw/i2c/i2c_mux_pca954x.h"

#define MIN_PAGE_BITS   12
#define RAM_SIZE    0x40000000
static const MemMapEntry HI1711_memmap[] = {
    [HI1711_DDR]            = {0x80000000, RAM_SIZE},

    [HI1711_UART0]          = {0x08710000, 0x1000},
    [HI1711_UART1]          = {0x08711000, 0x1000},
    [HI1711_UART2]          = {0x08743000, 0x1000},
    [HI1711_UART3]          = {0x08744000, 0x1000},
    [HI1711_UART4]          = {0x0875D000, 0x1000},
    [HI1711_UART5]          = {0x0875E000, 0x1000},

    [HI1711_GIC_GICD]       = {0x24000000, 0x10000},
    [HI1711_GIC_GICR]       = {0x24040000, 0x100000},

    [HI1711_GPIO0]          = {0x0874a000, 0x1000},
    [HI1711_GPIO1]          = {0x0874b000, 0x1000},
    [HI1711_GPIO2]          = {0x0874c000, 0x1000},
    [HI1711_GPIO3]          = {0x0874d000, 0x1000},
    [HI1711_GPIO4]          = {0x0874e000, 0x1000},

    [HI1711_MDIO0]          = {0x08747000, 0x1000},

    [HI1711_GMAC0]          = {0x0cd00000, 0x1000},
    [HI1711_GMAC1]          = {0x0cd01000, 0x1000},
    [HI1711_GMAC2]          = {0x0cd02000, 0x1000},
    [HI1711_GMAC3]          = {0x0cd03000, 0x1000},

    [HI1711_VIRTIO0]        = {0x5e681000, 0x1000},
    [HI1711_VIRTIO1]        = {0x5e682000, 0x1000},
	[HI1711_VIRTIO2]        = {0x5e683000, 0x1000},

    [HI1711_I2C0]           = {0x08707000, 0x1000},
    [HI1711_I2C1]           = {0x08708000, 0x1000},
    [HI1711_I2C2]           = {0x08709000, 0x1000},
    [HI1711_I2C3]           = {0x0870A000, 0x1000},
    [HI1711_I2C4]           = {0x0870B000, 0x1000},
    [HI1711_I2C5]           = {0x0870C000, 0x1000},
    [HI1711_I2C6]           = {0x0870D000, 0x1000},
    [HI1711_I2C7]           = {0x0870E000, 0x1000},
    [HI1711_I2C8]           = {0x08750000, 0x1000},
    [HI1711_I2C9]           = {0x08751000, 0x1000},
    [HI1711_I2C10]          = {0x08752000, 0x1000},
    [HI1711_I2C11]          = {0x08753000, 0x1000},
    [HI1711_I2C12]          = {0x08754000, 0x1000},
    [HI1711_I2C13]          = {0x08755000, 0x1000},
    [HI1711_I2C14]          = {0x08756000, 0x1000},
    [HI1711_I2C15]          = {0x08757000, 0x1000},

	[HI1711_IPMB0]           = {0x08716000, 0x1000},
    [HI1711_IPMB1]           = {0x08717000, 0x1000},
    [HI1711_IPMB2]           = {0x08718000, 0x1000},
    [HI1711_IPMB3]           = {0x08719000, 0x1000},

    [HI1711_TRNG]           = {0X0876C000, 0x10000},

    [HI1711_LP_SUBSYS]      = {0X0871d000, 0x1000},

    [HI1711_WDG0]           = {0X08763000, 0x1000},
    [HI1711_WDG1]           = {0X08764000, 0x1000},
    [HI1711_WDG2]           = {0X08765000, 0x1000},
    [HI1711_WDG3]           = {0X08766000, 0x1000},
    [HI1711_WDG4]           = {0X08767000, 0x1000},
    [HI1711_WDG5]           = {0X08768000, 0x1000},

    [HI1711_EFUSE0]         = {0X08540000, 0x10000},
    [HI1711_EFUSE1]         = {0X08770000, 0x10000},

    [HI1711_LOCALBUS]       = {0x08712000, 0x1000},

};

static const int irqmap[] = {
    [HI1711_UART0] = 58,
    [HI1711_UART1] = 59,
    [HI1711_UART2] = 60,
    [HI1711_UART3] = 61,
    [HI1711_UART4] = 62,
    [HI1711_UART5] = 63,

    [HI1711_GPIO0] = 149,
    [HI1711_GPIO1] = 150,
    [HI1711_GPIO2] = 151,
    [HI1711_GPIO3] = 152,
    [HI1711_GPIO4] = 153,

    [HI1711_MDIO0] = 137,

    [HI1711_GMAC0] = 52,
    [HI1711_GMAC1] = 53,
    [HI1711_GMAC2] = 54,
    [HI1711_GMAC3] = 55,

    [HI1711_VIRTIO0] = 102,
    [HI1711_VIRTIO1] = 103,
	[HI1711_VIRTIO2] = 104,

    [HI1711_I2C0]       = 72,
    [HI1711_I2C1]       = 73,
    [HI1711_I2C2]       = 74,
    [HI1711_I2C3]       = 75,
    [HI1711_I2C4]       = 76,
    [HI1711_I2C5]       = 77,
    [HI1711_I2C6]       = 78,
    [HI1711_I2C7]       = 79,
    [HI1711_I2C8]       = 80,
    [HI1711_I2C9]       = 81,
    [HI1711_I2C10]      = 82,
    [HI1711_I2C11]      = 83,
    [HI1711_I2C12]      = 84,
    [HI1711_I2C13]      = 85,
    [HI1711_I2C14]      = 86,
    [HI1711_I2C15]      = 87,

	[HI1711_IPMB0]       = 132,
    [HI1711_IPMB1]       = 133,
    [HI1711_IPMB2]       = 134,
    [HI1711_IPMB3]       = 135,

    [HI1711_TRNG]       = 39,

    [HI1711_LOCALBUS]  = 111,
};

static struct arm_boot_info binfo = {
    /* No board ID, we boot from DT tree */
    .board_id = -1,
};

static void hi1711_modify_dtb(const struct arm_boot_info *info, void *fdt)
{
    int offset;

    /* uart clock freq adjust */
    offset = fdt_path_offset(fdt, "/memory");
    if (offset > 0) {
        uint32_t reg[4] = {0x0, 0x87200000, 0x0, 0x40000000};
        int ret = fdt_setprop(fdt, offset, "reg", reg, sizeof(reg));
        if (ret != 0) {
            error_report("hi1711_modify_dtb is failed to set rsv-ram\n");
        }
    } else {
        error_report("hi1711_modify_dtb is not find memory\n");
    }
}

static void create_eeprom(HI1711_MachineState* ms, MachineState *machine, uint8_t addr)
{
    DeviceState *eeprom_1 = DEVICE(i2c_slave_new("eeprom-i2c-slave", addr));
    qdev_prop_set_uint8(eeprom_1, "reg-id", 0x01);
    i2c_slave_realize_and_unref(I2C_SLAVE(eeprom_1), (I2CBus *)qdev_get_child_bus(ms->i2c[1], "i2c"), &error_abort);
    

    DeviceState *eeprom_2 = DEVICE(i2c_slave_new("eeprom-i2c-slave", addr));
    qdev_prop_set_uint8(eeprom_2, "reg-id", 0x02);
    i2c_slave_realize_and_unref(I2C_SLAVE(eeprom_2), (I2CBus *)qdev_get_child_bus(ms->i2c[2], "i2c"), &error_abort);
    

    DeviceState *eeprom_4 = DEVICE(i2c_slave_new("eeprom-i2c-slave", addr));
    qdev_prop_set_uint8(eeprom_4, "reg-id", 0x04);
    i2c_slave_realize_and_unref(I2C_SLAVE(eeprom_4), (I2CBus *)qdev_get_child_bus(ms->i2c[4], "i2c"), &error_abort);
    

    DeviceState *eeprom_5 = DEVICE(i2c_slave_new("eeprom-i2c-slave", addr));
    qdev_prop_set_uint8(eeprom_5, "reg-id", 0x05);
    i2c_slave_realize_and_unref(I2C_SLAVE(eeprom_5), (I2CBus *)qdev_get_child_bus(ms->i2c[5], "i2c"), &error_abort);
    

    DeviceState *eeprom_8 = DEVICE(i2c_slave_new("eeprom-i2c-slave", addr));
    qdev_prop_set_uint8(eeprom_8, "reg-id", 0x08);
    i2c_slave_realize_and_unref(I2C_SLAVE(eeprom_8), (I2CBus *)qdev_get_child_bus(ms->i2c[8], "i2c"), &error_abort);

    DeviceState *eeprom_12 = DEVICE(i2c_slave_new("eeprom-i2c-slave", addr));
    qdev_prop_set_uint8(eeprom_12, "reg-id", 0x0c);
    i2c_slave_realize_and_unref(I2C_SLAVE(eeprom_12), (I2CBus *)qdev_get_child_bus(ms->i2c[12], "i2c"), &error_abort);
    
	
	DeviceState *eeprom_14 = DEVICE(i2c_slave_new("eeprom-i2c-slave", addr));
    qdev_prop_set_uint8(eeprom_14, "reg-id", 0x0e);
    i2c_slave_realize_and_unref(I2C_SLAVE(eeprom_14), (I2CBus *)qdev_get_child_bus(ms->i2c[14], "i2c"), &error_abort);
}

static void create_lm75(HI1711_MachineState* ms, MachineState *machine, uint8_t addr)
{
    DeviceState *lm75_8 = DEVICE(i2c_slave_new("lm75-i2c-slave", addr));
    qdev_prop_set_uint8(lm75_8, "reg-id", 0x08);
    i2c_slave_realize_and_unref(I2C_SLAVE(lm75_8), (I2CBus *)qdev_get_child_bus(ms->i2c[8], "i2c"), &error_abort);
    

    DeviceState *lm75_11 = DEVICE(i2c_slave_new("lm75-i2c-slave", addr));
    qdev_prop_set_uint8(lm75_11, "reg-id", 0x0b);
    i2c_slave_realize_and_unref(I2C_SLAVE(lm75_11), (I2CBus *)qdev_get_child_bus(ms->i2c[11], "i2c"), &error_abort);
    
}

static void create_mcu(HI1711_MachineState* ms, MachineState *machine, uint8_t addr)
{
    DeviceState *mcu_12 = DEVICE(i2c_slave_new("mcu-i2c-slave", addr));
    qdev_prop_set_uint8(mcu_12, "reg-id", 0x0c);
    i2c_slave_realize_and_unref(I2C_SLAVE(mcu_12), (I2CBus *)qdev_get_child_bus(ms->i2c[12], "i2c"), &error_abort);
}

static void create_smc(HI1711_MachineState* ms, MachineState *machine, uint8_t addr)
{
    DeviceState *smc_1 = DEVICE(i2c_slave_new("smc-i2c-slave", addr));
    qdev_prop_set_uint8(smc_1, "reg-id", 0x01);
    i2c_slave_realize_and_unref(I2C_SLAVE(smc_1), (I2CBus *)qdev_get_child_bus(ms->i2c[1], "i2c"), &error_abort);
    

    DeviceState *smc_2 = DEVICE(i2c_slave_new("smc-i2c-slave", addr));
    qdev_prop_set_uint8(smc_2, "reg-id", 0x02);
    i2c_slave_realize_and_unref(I2C_SLAVE(smc_2), (I2CBus *)qdev_get_child_bus(ms->i2c[2], "i2c"), &error_abort);
    

    DeviceState *smc_4 = DEVICE(i2c_slave_new("smc-i2c-slave", addr));
    qdev_prop_set_uint8(smc_4, "reg-id", 0x04);
    i2c_slave_realize_and_unref(I2C_SLAVE(smc_4), (I2CBus *)qdev_get_child_bus(ms->i2c[4], "i2c"), &error_abort);
    

    DeviceState *smc_5 = DEVICE(i2c_slave_new("smc-i2c-slave", addr));
    qdev_prop_set_uint8(smc_5, "reg-id", 0x05);
    i2c_slave_realize_and_unref(I2C_SLAVE(smc_5), (I2CBus *)qdev_get_child_bus(ms->i2c[5], "i2c"), &error_abort);
    
}

static void create_pca9555(HI1711_MachineState* ms, MachineState *machine, uint8_t addr)
{
    DeviceState *pca9555_1 = DEVICE(i2c_slave_new("pca9555-i2c-slave", addr));
    qdev_prop_set_uint8(pca9555_1, "reg-id", 0x07);
    i2c_slave_realize_and_unref(I2C_SLAVE(pca9555_1), (I2CBus *)qdev_get_child_bus(ms->i2c[7], "i2c"), &error_abort);
}

static void create_pca9545(HI1711_MachineState* ms, MachineState *machine, uint8_t addr)
{
    I2CSlave *mux = i2c_slave_new("pca9548", addr);
    DeviceState *pca9545_1 = DEVICE(mux);
    i2c_slave_realize_and_unref(I2C_SLAVE(pca9545_1), (I2CBus *)qdev_get_child_bus(ms->i2c[6], "i2c"), &error_abort);

    DeviceState *eeprom_1 = DEVICE(i2c_slave_new("eeprom-i2c-slave", 0xae>>1));
    qdev_prop_set_uint8(eeprom_1, "reg-id", 0x06);
    qdev_prop_set_uint8(eeprom_1, "channel-id", 0x00);
    i2c_slave_realize_and_unref(I2C_SLAVE(eeprom_1), pca954x_i2c_get_bus(mux, 0), &error_abort);

    DeviceState *eeprom_2 = DEVICE(i2c_slave_new("eeprom-i2c-slave", 0xae>>1));
    qdev_prop_set_uint8(eeprom_2, "reg-id", 0x06);
    qdev_prop_set_uint8(eeprom_2, "channel-id", 0x02);
    i2c_slave_realize_and_unref(I2C_SLAVE(eeprom_2), pca954x_i2c_get_bus(mux, 2), &error_abort);
}

static void create_hi182x(HI1711_MachineState* ms, MachineState *machine, uint8_t addr)
{
    DeviceState *hi182x_12 = DEVICE(i2c_slave_new("hi182x-i2c-slave", addr));
    qdev_prop_set_uint8(hi182x_12, "reg-id", 0x0c);
    i2c_slave_realize_and_unref(I2C_SLAVE(hi182x_12), (I2CBus *)qdev_get_child_bus(ms->i2c[12], "i2c"), &error_abort);

    DeviceState *hi182x_14 = DEVICE(i2c_slave_new("hi182x-i2c-slave", addr));
    qdev_prop_set_uint8(hi182x_14, "reg-id", 0x0e);
    i2c_slave_realize_and_unref(I2C_SLAVE(hi182x_14), (I2CBus *)qdev_get_child_bus(ms->i2c[14], "i2c"), &error_abort);
}

static void hi1711_board_init(MachineState *machine)
{
    HI1711_MachineState *s;

    s = HI1711(object_new(TYPE_HI1711));
    object_property_add_child(OBJECT(machine), "soc", OBJECT(s));

    s->memmap = (MemMapEntry *)HI1711_memmap;
    s->irqmap = (int*)irqmap;

    qdev_realize(DEVICE(s), NULL, &error_abort);

    memory_region_init_ram(&s->ram, NULL, "hi1711.ram.1", machine->ram_size, &error_abort);
    memory_region_add_subregion(get_system_memory(), HI1711_memmap[HI1711_DDR].base, &s->ram);

    create_unimplemented_device("local-bus", 0x00000000, 0x08000000);
    create_unimplemented_device("mmc", 0x0871D000, 0x1000);
    create_unimplemented_device("hp-subsys", 0xcd0c000, 0x1000);
    create_unimplemented_device("smbus", 0x08740000, 0x1000);
    create_unimplemented_device("i2c-16", 0x08745000, 0x1000);
    create_unimplemented_device("i2c-17", 0x0876e000, 0x1000);
    create_unimplemented_device("mdio", 0x08747000, 0x1000);
    create_unimplemented_device("cpld", 0x40000000, 0x1000);

    create_eeprom(s, machine, 0xae >> 1);
    create_lm75(s, machine, 0x90 >> 1);
    create_mcu(s, machine, 0xc8 >> 1);
    create_smc(s, machine, 0x60 >> 1);
    create_pca9555(s, machine, 0x42 >> 1);
    create_pca9545(s, machine, 0xe0 >> 1);
    create_hi182x(s, machine, 0xe8 >> 1);



    binfo = (struct arm_boot_info) {
        .ram_size = machine->ram_size,
        .nb_cpus = machine->smp.cpus,
        .secure_boot = false,
        .modify_dtb = hi1711_modify_dtb,
        
        .loader_start = s->memmap[HI1711_DDR].base + HI1711_LOADER_START,
    };

    if (!qtest_enabled()) {
        arm_load_kernel(&s->cpu[0], machine, &binfo);
    }
}

static void hi1711_machine_init(MachineClass *mc)
{
    mc->desc = "Hi1711 Boards (Cortex-A55)";
    mc->init = hi1711_board_init;
    mc->max_cpus = HI1711_NUM_CPUS;
    mc->minimum_page_bits = MIN_PAGE_BITS;
    mc->ignore_memory_transaction_failures = true;
    mc->default_ram_size = RAM_SIZE;
}

static void hi1711_machine_init_class_init(ObjectClass *oc, void *data)
{
    MachineClass *mc = MACHINE_CLASS(oc);
    hi1711_machine_init(mc);
}

static void hi1711_machine_instance_init(Object *obj)
{
}

static const TypeInfo hi1711_machine_init_typeinfo = {
    .name       = MACHINE_TYPE_NAME("hi1711"),
    .parent     = TYPE_MACHINE,
    .class_init = hi1711_machine_init_class_init,
    .instance_size = sizeof(HI1711_MachineState),
    .instance_init = hi1711_machine_instance_init,
};

static void hi1711_machine_init_register_types(void)
{
    type_register_static(&hi1711_machine_init_typeinfo);
}

type_init(hi1711_machine_init_register_types)
